Todo:

# load libraries and read data
library(tidyverse)
library(readxl)
library(plotly)

ghg_emissions_clean <- read_csv("data/clean_data/ghg_emissions.csv")

-- Column specification ----------------------------------------------------------------------------------------------------------------------------
cols(
  ccp_mapping = col_character(),
  source_name = col_character(),
  pollutant = col_character(),
  year = col_double(),
  value = col_double(),
  units = col_character()
)

Only emissions - > emissions that are greater than 0

ghg_true_emissions <- ghg_emissions_clean %>% 
  filter(year == max(ghg_true_emissions$year)) %>% 
  filter(value >= 0) %>% 
  mutate(across(where(is.character), ~str_to_title(.)))
# need to split by pollutant and year
ghg_emissions_clean %>% 
  select(ccp_mapping, source_name) %>% 
  filter(str_detect(source_name, paste("^", ccp_mapping, sep = ""))) %>% 
  unique()
n_breaks <- max(str_count(ghg_emissions_clean$source_name, " - "), na.rm = TRUE)

n_children <- n_breaks + 1

child_names <- c()

for (i in seq(1:n_children)) {
  child_name <- paste("child_order_", i, sep = "")
  child_names <- c(child_names, child_name)
}
# clean source name column and split into child columns
ghg_wide <- ghg_emissions_clean %>% 
  mutate(source_name = str_to_title(
    str_remove(
      source_name,
      paste("^", ccp_mapping, " - ", sep = "")
      ))) %>% 
  separate(source_name, into = child_names, sep = " - ", fill = "right") %>% 
  rename(child_order_0 = ccp_mapping)
ghg_wide_emissions <- ghg_wide %>%
  filter(!value < 0)

ghg_wide_sinks <- ghg_wide %>% 
  filter(value < 0)
ghg_wide_emissions %>% 
  group_by(child_order_0, pollutant, year) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  # id must be created, parents are null - this is the top level
  mutate(id = child_order_0, parent = "") %>% 
  select(id, label = child_order_0, parent, pollutant, year, value)
NA
ghg_wide_emissions %>%
  group_by(child_order_2, child_order_1, child_order_0, pollutant, year) %>% 
  summarise(value = sum(value), .groups = "drop") %>% 
  mutate(id = paste(child_order_0, child_order_1, child_order_2, sep = " - "),
         parent = paste(child_order_0, child_order_1, sep = " - ")) %>% 
  select(id, label = child_order_2, parent, pollutant, year, value)
ghg_wide_emissions %>%
  group_by(child_order_3, child_order_2, child_order_1, child_order_0, pollutant, year) %>% 
  summarise(value = sum(value), .groups = "drop") %>% 
  mutate(id = paste(child_order_0, child_order_1, child_order_2, child_order_3, sep = " - "),
         parent = paste(child_order_0, child_order_1, child_order_2, sep = " - ")) %>% 
  select(id, label = child_order_3, parent, pollutant, year, value)
create_child_table <- function(df, current_child, previous_children, additional_vars) {
  df %>% 
}

df %>% group_by(current_child, rev(previous_children), additional_vars) %>% summarise(value = sum(value), .groups = “drop”) %>% mutate(id = paste(previous_children, current_child, sep = " - “), parent = paste(previous_children, sep =” - ")) %>% select(id, label = current_child, parent, additional_vars, value)

vector <- c("child_1", "child_2")

paste(paste(vector, collapse = " - "),"child_3", sep = " - ")
[1] "child_1 - child_2 - child_3"
vector <- c()

paste(paste(vector, sep = " - "),"child_3", sep = " - ")
[1] " - child_3"
vector <- c()

tibble(
  parent = c("bean", "curd", "whey", "sprout", ""),
  people = c("david", "sasha", "john", "smith", "delilah"),
  shapes = c("triangle", "rectangle", "square", "diamond", "")
) %>% 
  unite(c(1,2,3), col = "id", sep = " - ", remove = FALSE)
tibble(
  parent = c("dad", "bean", "", "fava"),
  child = c("")
) %>% 
  select(child) %>% 
  pull()
[1] "" "" "" ""
# get sector totals for parent df (top level)

ghg_sector_totals <- ghg_true_emissions %>% 
  group_by(ccp_mapping) %>% 
  summarise(sector_total = sum(value), .groups = "drop_last")

parent_df <- ghg_sector_totals %>% 
  mutate(parent = "") %>% 
  select(label = ccp_mapping,
         parent,
         value = sector_total)

# the rest of the data

children_df <- ghg_true_emissions %>% 
  filter(year == max(ghg_true_emissions$year)) %>% 
  group_by(source_name, ccp_mapping) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  select(label = source_name,
         parent = ccp_mapping,
         value)

# combine into one hierarchical df, create id column

emissions_long <- bind_rows(list(parent_df, children_df)) %>% 
  mutate(id = paste(parent, label, sep = " - "), .before = 'label') %>% 
  mutate(id = str_remove(id, "^ - "))

Other method - seperate column

parents <- emissions_wide %>% 
  filter(is.na(second)) %>% 
  select(id, label, parent, value)
first_born <- emissions_wide %>% 
  filter(!is.na(second)) %>% 
  group_by(second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = second,
         parent = first,
         value)
second_born <- emissions_wide %>% 
  filter(!is.na(third)) %>% 
  group_by(third, second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, third, sep = " - ")) %>% 
  mutate(parent = paste(first, second, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = third,
         parent,
         value)
third_born <- emissions_wide %>% 
  filter(!is.na(fourth)) %>% 
  group_by(fourth, third, second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, third, fourth, sep = " - ")) %>% 
  mutate(parent = paste(first, second, third, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = fourth,
         parent,
         value)
n_potential_child_layers <- emissions_long %>% 
  select(id) %>% 
  pull() %>% 
  str_count(" - ") %>% 
  max()
create_hierarchy_df <- function(df, id_col = "id", id_sep = " - ") {
  n_potential_child_layers <- df %>% 
    select(col) %>% 
    pull() %>% 
    str_count(sep) %>% 
    max()
  
  
}
emissions_long %>% 
  data.frame(stringsAsFactors = FALSE) %>% 
  plot_ly(
    ids = ~id,
    labels = ~label,
    parents = ~parent,
    values = ~value,
    type = "sunburst",
    maxdepth = 2,
    insidetextorientation = 'radial',
    marker=list(colorscale='Portland'),
    text = ~units,
    textinfo='label+percent root+percent entry',
    hoverinfo = paste("%{label}: <br>%{value}",'text')
  )
plot_ly(
  labels = c("Eve", "Seth", "Enos", "Noam", "Awan", "Enoch"),
  parents = c("", "Eve", "Seth", "Seth", "Eve", "Awan"),
  values = c(16, 12, 10, 2, 4, 4),
  type = "sunburst",
  branchvalues = "total"
)
tibble(
  labels = c("Eve", "Seth", "Enos", "Noam", "Awan", "Enoch"),
  parents = c("", "Eve", "Seth", "Seth", "Eve", "Awan"),
  values = c(16, 12, 10, 2, 4, 4)
)
fig <- plot_ly(
  labels = cain_ble$labels,
  parents = cain_ble$parents,
  values = cain_ble$values,
  type = 'sunburst'
)

fig
emissions_long$label[1:10]
 [1] "Agriculture"            "Electricity Generation" "Industry"               "Land use"               "Residential"           
 [6] "Services"               "Transport"              "Waste"                  "Accidental fires"       "Accidental fires"      
d <- data.frame(
    ids = c(
    "North America", "Europe", "Australia", "North America - Football", "Soccer",
    "North America - Rugby", "Europe - Football", "Rugby",
    "Europe - American Football","Australia - Football", "Association",
    "Australian Rules", "Autstralia - American Football", "Australia - Rugby",
    "Rugby League", "Rugby Union"
  ),
  labels = c(
    "North<br>America", "Europe", "Australia", "Football", "Soccer", "Rugby",
    "Football", "Rugby", "American<br>Football", "Football", "Association",
    "Australian<br>Rules", "American<br>Football", "Rugby", "Rugby<br>League",
    "Rugby<br>Union"
  ),
  parents = c(
    "", "", "", "North America", "North America", "North America", "Europe",
    "Europe", "Europe","Australia", "Australia - Football", "Australia - Football",
    "Australia - Football", "Australia - Football", "Australia - Rugby",
    "Australia - Rugby"
  ),
  stringsAsFactors = FALSE
)

fig <- plot_ly(d, ids = ~ids, labels = ~labels, parents = ~parents, type = 'sunburst')

d
class(emissions_long)
[1] "tbl_df"     "tbl"        "data.frame"
class(cain_ble)
[1] "tbl_df"     "tbl"        "data.frame"
diff_order <- ghg_emissions_clean %>% 
  dplyr::group_by(ccp_mapping, year, pollutant) %>% 
  dplyr::summarise(value = sum(value), units = units[1], .groups = "keep") %>%
  filter(pollutant == "CO2") %>% 
  filter(year == min(ghg_emissions_clean$year) |
           year == max(ghg_emissions_clean$year)) %>% 
  ungroup() %>% 
  group_by(ccp_mapping) %>% 
  mutate(diff = lag(value) - value) %>% 
  arrange(diff) %>%
  drop_na() %>% 
  select(ccp_mapping) %>% 
  pull()
ghg_emissions_clean %>% 
  dplyr::group_by(ccp_mapping, year, pollutant) %>% 
  dplyr::summarise(value = sum(value), units = units[1], .groups = "keep") %>%
  filter(pollutant == "CO2") %>%
  mutate(ccp_mapping = factor(ccp_mapping, levels = rev(diff_order))) %>% 
  ggplot() +
  aes(x = year, y = value, fill = ccp_mapping) +
  geom_area() +
  facet_wrap(~pollutant) +
  theme_bw()
ghg_emissions_clean %>% 
  group_by(pollutant) %>% 
  summarise(emissions = sum(value))
plotly::ggplotly(
  ghg_emissions_clean %>% 
    filter(year == 2018) %>%
    filter(pollutant %in% c("CO2", "CH4")) %>%
    ggplot() +
    aes(x = factor(ccp_mapping, levels = rev(levels(factor(ccp_mapping)))),
        y = value, fill = source_name,
        text = paste0('</br> Sector: ', ccp_mapping,
                      '</br> Emissions: ', value,
                      '</br> Source Name: ', source_name)) +
    geom_col(position = "stack") +
    theme_bw() +
    theme(legend.position = "none") +
    labs(x = "Sector",
         y = paste0("Emissions (", ghg_emissions_clean$units[1], ")")) +
    coord_flip(),
    tooltip = 'text'
  )
ghg_emissions_data %>% 
  names()
ghg_emissions_data %>% 
  select()
input <- list()

input$col_choice = "national_communication_categories"
ghg_emissions_clean %>%
  group_by_(input$col_choice, "emission_year") %>% 
  summarise(total_ghg_emissions = sum(emissions)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions, group = `National Communication Categories`, colour = `National Communication Categories`) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5)) +
  theme(legend.position = 0)
ghg_emissions_data %>% 
  distinct(`National Communication Categories`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5)) +
  ylim(0, 80) +
  theme(legend.position = 0) +
  theme_bw()
ghg_emissions_data %>% 
  distinct(`CCP mapping`)
ghg_emissions_data %>% 
  distinct(`National Communication Categories`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(`CCP mapping`, EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions, group = `CCP mapping`, colour = `CCP mapping`) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5))
`summarise()` regrouping output by 'CCP mapping' (override with `.groups` argument)

ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  filter(`National Communication Categories` != `CCP mapping`) %>% 
  select(`National Communication Categories`, `CCP mapping`) %>% 
  unique()

category_id,category_name,subcategory_id,subcategory_name,year,emissions,emission

emissions_sankey <- emissions_data %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units)
filtered_df <- ghg_emissions_clean %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units) %>% 
  filter(pollutant == "CO2") %>% 
  filter(emission_year == "2005")
total_emissions_for_gas <- filtered_df %>% 
  summarise(sum(emissions)) %>% 
  pull()

total_emissions_by_category <- filtered_df %>% 
  select(-pollutant) %>% 
  group_by(ccp_mapping) %>% 
  summarise(cat_sum = sum(emissions), .groups = 'drop_last')
categories <- filtered_df %>% 
  distinct(ccp_mapping) %>% 
  pull()

n_categories <- length(categories)

sources <- filtered_df %>% 
  distinct(source_name) %>% 
  pull()

n_sources <- length(sources)
n_sources
[1] 159
node_names <- c("Total", categories, sources, "Other")

node_names_df <- data.frame("name" = node_names)

total_sankey_tibble <- total_emissions_by_category %>%
  mutate(total = "Total") %>% 
  mutate(total = match(total, node_names) -1) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1) %>% 
  select(source = total,
         target = ccp_mapping,
         value = cat_sum)

total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)


sub_sankey_tibble <- filtered_df %>% 
  select(- c(units, pollutant, emission_year)) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1,
         source_name = match(source_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)

sub_sankey_tibble <- filtered_tibble %>% 
  select(-category_id, -subcategory_id, -year) %>% 
  mutate(category_name = match(category_name, node_names) -1,
         subcategory_name = match(subcategory_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
make_sankey_dfs <- function(data, userYear, userGas) {
  n_categories <- data %>% 
    distinct(category_name) %>% 
    nrow()
  
  total_emissions_for_gas <- data %>% 
    filter(emission == userGas()) %>% 
    filter(year == userYear()) %>%
    summarise(sum(emissions)) %>% 
    pull()
  
  filtered_tibble <- data %>%
    filter(emission == userGas()) %>% 
    select(-emission) %>% 
    filter(year == userYear()) %>% 
    filter(emissions > userResolution())
  
  total_emissions_by_cat <- filtered_tibble %>%
    group_by(category_name) %>% 
    summarise(cat_sum = sum(emissions), .groups = 'drop_last')
  
  categories <- filtered_tibble %>%
    distinct(category_name) %>% 
    pull()
  
  subcategories <- filtered_tibble %>%
    distinct(subcategory_name) %>% 
    pull()
  
  node_names <- c("Total", categories, subcategories, "Other")
  
  node_names_df <- data.frame("name" = node_names)
  
  total_sankey_tibble <- total_emissions_by_cat %>%
    mutate(total = "Total") %>% 
    mutate(total = match(total, node_names) -1) %>% 
    mutate(category_name = match(category_name, node_names) -1) %>% 
    select(source = total,
           target = category_name,
           value = cat_sum)
  
  total_filtered_emissions <- total_sankey_tibble %>% 
    summarise(sum(value)) %>% 
    pull()
  
  other_emissions <- total_emissions_for_gas - total_filtered_emissions
  
  total_other_sankey_tibble <- tibble(
    "source" = c(0),
    "target" = (match("Other", node_names) -1),
    "value" = c(other_emissions)
  )
  
  sub_sankey_tibble <- filtered_tibble %>% 
    select(-category_id, -subcategory_id, -year) %>% 
    mutate(category_name = match(category_name, node_names) -1,
           subcategory_name = match(subcategory_name, node_names) -1)
  
  names(sub_sankey_tibble) = c("source", "target", "value")
  
  sankey_tibble <- total_sankey_tibble %>% 
    bind_rows(sub_sankey_tibble) %>% 
    bind_rows(total_other_sankey_tibble)
  
  links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))
  
  # Add a 'group' column to each connection:
  links <- links_matrix %>% 
    mutate(group = case_when(
      source == 0 ~ paste("type_", target, sep = ""),
      source!=0 ~ paste("type_", source, sep = "")
    ))
  
  nodes <- node_names_df
  # Add a 'group' column to each node.
  # All of them in the same group to make them the same colour
  nodes$group <- as.factor(c("my_unique_group"))
  
  emissions <- list()
  
  emissions$nodes <- nodes
  emissions$links <- links
  
  return(emissions)
}
make_sankey_dfs(emissions_sankey, userYear = 2005, userGas = "CH4", userResolution = 50)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBUb2RvOg0KDQotIGFkZCBjb2x1bW5zIGZvciB0b3RhbHMgZm9yIGVhY2ggcG9sbHV0YW50L3NlY3Rvcg0KDQpgYGB7cn0NCiMgbG9hZCBsaWJyYXJpZXMgYW5kIHJlYWQgZGF0YQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkocGxvdGx5KQ0KDQpnaGdfZW1pc3Npb25zX2NsZWFuIDwtIHJlYWRfY3N2KCJkYXRhL2NsZWFuX2RhdGEvZ2hnX2VtaXNzaW9ucy5jc3YiKQ0KYGBgDQoNCk9ubHkgZW1pc3Npb25zIC0gPiBlbWlzc2lvbnMgdGhhdCBhcmUgZ3JlYXRlciB0aGFuIDANCg0KYGBge3J9DQpnaGdfdHJ1ZV9lbWlzc2lvbnMgPC0gZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUgDQogIGZpbHRlcih5ZWFyID09IG1heChnaGdfdHJ1ZV9lbWlzc2lvbnMkeWVhcikpICU+JSANCiAgZmlsdGVyKHZhbHVlID49IDApICU+JSANCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCB+c3RyX3RvX3RpdGxlKC4pKSkNCmBgYA0KDQpgYGB7cn0NCiMgbmVlZCB0byBzcGxpdCBieSBwb2xsdXRhbnQgYW5kIHllYXINCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBzZWxlY3QoY2NwX21hcHBpbmcsIHNvdXJjZV9uYW1lKSAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHNvdXJjZV9uYW1lLCBwYXN0ZSgiXiIsIGNjcF9tYXBwaW5nLCBzZXAgPSAiIikpKSAlPiUgDQogIHVuaXF1ZSgpDQpgYGANCg0KYGBge3J9DQojIHZhcl9uYW1lcw0KDQojIGdldCBudW1iZXIgb2Ygc2VwYXJhdG9ycyBpbiBzb3VyY2UgY29sdW1uDQpuX2JyZWFrcyA8LSBtYXgoc3RyX2NvdW50KGdoZ19lbWlzc2lvbnNfY2xlYW4kc291cmNlX25hbWUsICIgLSAiKSwgbmEucm0gPSBUUlVFKQ0KDQojIG51bWJlciBvZiBwb3RlbnRpYWwgY2hpbGRyZW4gID0gbnVtYmVyIG9mIGJyZWFrcyArIDENCiMgc2luY2U6ICJvbmUiIC0gInR3byIgLSAidGhyZWUiDQpuX2NoaWxkcmVuIDwtIG5fYnJlYWtzICsgMQ0KDQojIGNyZWF0ZSB2ZWN0b3IgYW5kIGZpbGwgd2l0aCBjaGlsZG5hbWVzDQpjaGlsZF9uYW1lcyA8LSBjKCkNCg0KZm9yIChpIGluIHNlcSgxOm5fY2hpbGRyZW4pKSB7DQogIGNoaWxkX25hbWUgPC0gcGFzdGUoImNoaWxkX29yZGVyXyIsIGksIHNlcCA9ICIiKQ0KICBjaGlsZF9uYW1lcyA8LSBjKGNoaWxkX25hbWVzLCBjaGlsZF9uYW1lKQ0KfQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgY2xlYW4gc291cmNlIG5hbWUgY29sdW1uIGFuZCBzcGxpdCBpbnRvIGNoaWxkIGNvbHVtbnMNCmdoZ193aWRlIDwtIGdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBtdXRhdGUoc291cmNlX25hbWUgPSBzdHJfdG9fdGl0bGUoDQogICAgc3RyX3JlbW92ZSgNCiAgICAgIHNvdXJjZV9uYW1lLA0KICAgICAgcGFzdGUoIl4iLCBjY3BfbWFwcGluZywgIiAtICIsIHNlcCA9ICIiKQ0KICAgICAgKSkpICU+JSANCiAgc2VwYXJhdGUoc291cmNlX25hbWUsIGludG8gPSBjaGlsZF9uYW1lcywgc2VwID0gIiAtICIsIGZpbGwgPSAicmlnaHQiKSAlPiUgDQogIHJlbmFtZShjaGlsZF9vcmRlcl8wID0gY2NwX21hcHBpbmcpDQpgYGANCg0KYGBge3J9DQpnaGdfd2lkZV9lbWlzc2lvbnMgPC0gZ2hnX3dpZGUgJT4lDQogIGZpbHRlcighdmFsdWUgPCAwKQ0KDQpnaGdfd2lkZV9zaW5rcyA8LSBnaGdfd2lkZSAlPiUgDQogIGZpbHRlcih2YWx1ZSA8IDApDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2hnX3dpZGVfZW1pc3Npb25zICU+JSANCiAgZ3JvdXBfYnkoY2hpbGRfb3JkZXJfMCwgcG9sbHV0YW50LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgJT4lIA0KICAjIGlkIG11c3QgYmUgY3JlYXRlZCwgcGFyZW50cyBhcmUgbnVsbCAtIHRoaXMgaXMgdGhlIHRvcCBsZXZlbA0KICBtdXRhdGUoaWQgPSBjaGlsZF9vcmRlcl8wLCBwYXJlbnQgPSAiIikgJT4lIA0KICBzZWxlY3QoaWQsIGxhYmVsID0gY2hpbGRfb3JkZXJfMCwgcGFyZW50LCBwb2xsdXRhbnQsIHllYXIsIHZhbHVlKQ0KDQpgYGANCg0KYGBge3J9DQpnaGdfd2lkZV9lbWlzc2lvbnMgJT4lDQogIGdyb3VwX2J5KGNoaWxkX29yZGVyXzEsIGNoaWxkX29yZGVyXzAsIHBvbGx1dGFudCwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogIG11dGF0ZShpZCA9IHBhc3RlKGNoaWxkX29yZGVyXzAsIGNoaWxkX29yZGVyXzEsIHNlcCA9ICIgLSAiKSwNCiAgICAgICAgIHBhcmVudCA9IGNoaWxkX29yZGVyXzApICU+JSANCiAgc2VsZWN0KGlkLCBsYWJlbCA9IGNoaWxkX29yZGVyXzEsIHBhcmVudCwgcG9sbHV0YW50LCB5ZWFyLCB2YWx1ZSkNCmBgYA0KDQpgYGB7cn0NCmdoZ193aWRlX2VtaXNzaW9ucyAlPiUNCiAgZ3JvdXBfYnkoY2hpbGRfb3JkZXJfMiwgY2hpbGRfb3JkZXJfMSwgY2hpbGRfb3JkZXJfMCwgcG9sbHV0YW50LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcCIpICU+JSANCiAgbXV0YXRlKGlkID0gcGFzdGUoY2hpbGRfb3JkZXJfMCwgY2hpbGRfb3JkZXJfMSwgY2hpbGRfb3JkZXJfMiwgc2VwID0gIiAtICIpLA0KICAgICAgICAgcGFyZW50ID0gcGFzdGUoY2hpbGRfb3JkZXJfMCwgY2hpbGRfb3JkZXJfMSwgc2VwID0gIiAtICIpKSAlPiUgDQogIHNlbGVjdChpZCwgbGFiZWwgPSBjaGlsZF9vcmRlcl8yLCBwYXJlbnQsIHBvbGx1dGFudCwgeWVhciwgdmFsdWUpDQpgYGANCg0KYGBge3J9DQpnaGdfd2lkZV9lbWlzc2lvbnMgJT4lDQogIGdyb3VwX2J5KGNoaWxkX29yZGVyXzMsIGNoaWxkX29yZGVyXzIsIGNoaWxkX29yZGVyXzEsIGNoaWxkX29yZGVyXzAsIHBvbGx1dGFudCwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogIG11dGF0ZShpZCA9IHBhc3RlKGNoaWxkX29yZGVyXzAsIGNoaWxkX29yZGVyXzEsIGNoaWxkX29yZGVyXzIsIGNoaWxkX29yZGVyXzMsIHNlcCA9ICIgLSAiKSwNCiAgICAgICAgIHBhcmVudCA9IHBhc3RlKGNoaWxkX29yZGVyXzAsIGNoaWxkX29yZGVyXzEsIGNoaWxkX29yZGVyXzIsIHNlcCA9ICIgLSAiKSkgJT4lIA0KICBzZWxlY3QoaWQsIGxhYmVsID0gY2hpbGRfb3JkZXJfMywgcGFyZW50LCBwb2xsdXRhbnQsIHllYXIsIHZhbHVlKQ0KYGBgDQoNCmBgYHtyfQ0KY3JlYXRlX2NoaWxkX3RhYmxlIDwtIGZ1bmN0aW9uKGRmLCBjdXJyZW50X2NoaWxkLCBwcmV2aW91c19jaGlsZHJlbiwgYWRkaXRpb25hbF92YXJzKSB7DQogIGRmICU+JSANCn0NCmBgYA0KDQoNCmRmICU+JQ0KICBncm91cF9ieShjdXJyZW50X2NoaWxkLCByZXYocHJldmlvdXNfY2hpbGRyZW4pLCBhZGRpdGlvbmFsX3ZhcnMpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIA0KICBtdXRhdGUoaWQgPSBwYXN0ZShwcmV2aW91c19jaGlsZHJlbiwgY3VycmVudF9jaGlsZCwgc2VwID0gIiAtICIpLA0KICAgICAgICAgcGFyZW50ID0gcGFzdGUocHJldmlvdXNfY2hpbGRyZW4sIHNlcCA9ICIgLSAiKSkgJT4lIA0KICBzZWxlY3QoaWQsIGxhYmVsID0gY3VycmVudF9jaGlsZCwgcGFyZW50LCBhZGRpdGlvbmFsX3ZhcnMsIHZhbHVlKQ0KDQpgYGB7cn0NCnZlY3RvciA8LSBjKCJjaGlsZF8xIiwgImNoaWxkXzIiKQ0KDQpwYXN0ZShwYXN0ZSh2ZWN0b3IsIGNvbGxhcHNlID0gIiAtICIpLCJjaGlsZF8zIiwgc2VwID0gIiAtICIpDQpgYGANCg0KYGBge3J9DQp2ZWN0b3IgPC0gYygpDQoNCnBhc3RlKHBhc3RlKHZlY3Rvciwgc2VwID0gIiAtICIpLCJjaGlsZF8zIiwgc2VwID0gIiAtICIpDQpgYGANCg0KDQpgYGB7cn0NCnZlY3RvciA8LSBjKCkNCg0KdGliYmxlKA0KICBwYXJlbnQgPSBjKCJiZWFuIiwgImN1cmQiLCAid2hleSIsICJzcHJvdXQiLCAiIiksDQogIHBlb3BsZSA9IGMoImRhdmlkIiwgInNhc2hhIiwgImpvaG4iLCAic21pdGgiLCAiZGVsaWxhaCIpLA0KICBzaGFwZXMgPSBjKCJ0cmlhbmdsZSIsICJyZWN0YW5nbGUiLCAic3F1YXJlIiwgImRpYW1vbmQiLCAiIikNCikgJT4lIA0KICB1bml0ZShjKDEsMiwzKSwgY29sID0gImlkIiwgc2VwID0gIiAtICIsIHJlbW92ZSA9IEZBTFNFKQ0KYGBgDQoNCg0KYGBge3J9DQp0aWJibGUoDQogIHBhcmVudCA9IGMoImRhZCIsICJiZWFuIiwgIiIsICJmYXZhIiksDQogIGNoaWxkID0gYygiIikNCikgJT4lIA0KICBzZWxlY3QoY2hpbGQpICU+JSANCiAgcHVsbCgpDQpgYGANCg0KDQpgYGB7cn0NCiMgZ2V0IHNlY3RvciB0b3RhbHMgZm9yIHBhcmVudCBkZiAodG9wIGxldmVsKQ0KDQpnaGdfc2VjdG9yX3RvdGFscyA8LSBnaGdfdHJ1ZV9lbWlzc2lvbnMgJT4lIA0KICBncm91cF9ieShjY3BfbWFwcGluZykgJT4lIA0KICBzdW1tYXJpc2Uoc2VjdG9yX3RvdGFsID0gc3VtKHZhbHVlKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKQ0KDQpwYXJlbnRfZGYgPC0gZ2hnX3NlY3Rvcl90b3RhbHMgJT4lIA0KICBtdXRhdGUocGFyZW50ID0gIiIpICU+JSANCiAgc2VsZWN0KGxhYmVsID0gY2NwX21hcHBpbmcsDQogICAgICAgICBwYXJlbnQsDQogICAgICAgICB2YWx1ZSA9IHNlY3Rvcl90b3RhbCkNCg0KIyB0aGUgcmVzdCBvZiB0aGUgZGF0YQ0KDQpjaGlsZHJlbl9kZiA8LSBnaGdfdHJ1ZV9lbWlzc2lvbnMgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSBtYXgoZ2hnX3RydWVfZW1pc3Npb25zJHllYXIpKSAlPiUgDQogIGdyb3VwX2J5KHNvdXJjZV9uYW1lLCBjY3BfbWFwcGluZykgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JSANCiAgc2VsZWN0KGxhYmVsID0gc291cmNlX25hbWUsDQogICAgICAgICBwYXJlbnQgPSBjY3BfbWFwcGluZywNCiAgICAgICAgIHZhbHVlKQ0KDQojIGNvbWJpbmUgaW50byBvbmUgaGllcmFyY2hpY2FsIGRmLCBjcmVhdGUgaWQgY29sdW1uDQoNCmVtaXNzaW9uc19sb25nIDwtIGJpbmRfcm93cyhsaXN0KHBhcmVudF9kZiwgY2hpbGRyZW5fZGYpKSAlPiUgDQogIG11dGF0ZShpZCA9IHBhc3RlKHBhcmVudCwgbGFiZWwsIHNlcCA9ICIgLSAiKSwgLmJlZm9yZSA9ICdsYWJlbCcpICU+JSANCiAgbXV0YXRlKGlkID0gc3RyX3JlbW92ZShpZCwgIl4gLSAiKSkNCmBgYA0KDQojIE90aGVyIG1ldGhvZCAtIHNlcGVyYXRlIGNvbHVtbg0KDQpgYGB7cn0NCmVtaXNzaW9uc193aWRlIDwtIGVtaXNzaW9uc19sb25nICU+JSANCiAgc2VwYXJhdGUoaWQsICIgLSAiLCBpbnRvID0gYygiZmlyc3QiLCAic2Vjb25kIiwgInRoaXJkIiwgImZvdXJ0aCIpLA0KICAgICAgICAgICByZW1vdmUgPSBGQUxTRSwgZXh0cmEgPSAibWVyZ2UiLCBmaWxsID0gInJpZ2h0IikNCmBgYA0KDQpgYGB7cn0NCnBhcmVudHMgPC0gZW1pc3Npb25zX3dpZGUgJT4lIA0KICBmaWx0ZXIoaXMubmEoc2Vjb25kKSkgJT4lIA0KICBzZWxlY3QoaWQsIGxhYmVsLCBwYXJlbnQsIHZhbHVlKQ0KYGBgDQoNCmBgYHtyfQ0KZmlyc3RfYm9ybiA8LSBlbWlzc2lvbnNfd2lkZSAlPiUgDQogIGZpbHRlcighaXMubmEoc2Vjb25kKSkgJT4lIA0KICBncm91cF9ieShzZWNvbmQsIGZpcnN0KSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgJT4lIA0KICBtdXRhdGUoaWQgPSBwYXN0ZShmaXJzdCwgc2Vjb25kLCBzZXAgPSAiIC0gIikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGlkLA0KICAgICAgICAgbGFiZWwgPSBzZWNvbmQsDQogICAgICAgICBwYXJlbnQgPSBmaXJzdCwNCiAgICAgICAgIHZhbHVlKQ0KYGBgDQoNCmBgYHtyfQ0Kc2Vjb25kX2Jvcm4gPC0gZW1pc3Npb25zX3dpZGUgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHRoaXJkKSkgJT4lIA0KICBncm91cF9ieSh0aGlyZCwgc2Vjb25kLCBmaXJzdCkgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JSANCiAgbXV0YXRlKGlkID0gcGFzdGUoZmlyc3QsIHNlY29uZCwgdGhpcmQsIHNlcCA9ICIgLSAiKSkgJT4lIA0KICBtdXRhdGUocGFyZW50ID0gcGFzdGUoZmlyc3QsIHNlY29uZCwgc2VwID0gIiAtICIpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHNlbGVjdChpZCwNCiAgICAgICAgIGxhYmVsID0gdGhpcmQsDQogICAgICAgICBwYXJlbnQsDQogICAgICAgICB2YWx1ZSkNCmBgYA0KDQpgYGB7cn0NCnRoaXJkX2Jvcm4gPC0gZW1pc3Npb25zX3dpZGUgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGZvdXJ0aCkpICU+JSANCiAgZ3JvdXBfYnkoZm91cnRoLCB0aGlyZCwgc2Vjb25kLCBmaXJzdCkgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JSANCiAgbXV0YXRlKGlkID0gcGFzdGUoZmlyc3QsIHNlY29uZCwgdGhpcmQsIGZvdXJ0aCwgc2VwID0gIiAtICIpKSAlPiUgDQogIG11dGF0ZShwYXJlbnQgPSBwYXN0ZShmaXJzdCwgc2Vjb25kLCB0aGlyZCwgc2VwID0gIiAtICIpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHNlbGVjdChpZCwNCiAgICAgICAgIGxhYmVsID0gZm91cnRoLA0KICAgICAgICAgcGFyZW50LA0KICAgICAgICAgdmFsdWUpDQpgYGANCg0KYGBge3J9DQojIHRoZSBudW1iZXIgb2YgcG90ZW50aWFsIGNoaWxkIGxheWVycyBpcyB0aGUgbWF4aW11bSBpbmNsdWRlZCBpbiB0aGUgZGF0YXNldA0Kbl9wb3RlbnRpYWxfY2hpbGRfbGF5ZXJzIDwtIGVtaXNzaW9uc19sb25nICU+JSANCiAgc2VsZWN0KGlkKSAlPiUgDQogIHB1bGwoKSAlPiUgDQogIHN0cl9jb3VudCgiIC0gIikgJT4lIA0KICBtYXgoKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmNyZWF0ZV9oaWVyYXJjaHlfZGYgPC0gZnVuY3Rpb24oZGYsIGlkX2NvbCA9ICJpZCIsIGlkX3NlcCA9ICIgLSAiKSB7DQogIG5fcG90ZW50aWFsX2NoaWxkX2xheWVycyA8LSBkZiAlPiUgDQogICAgc2VsZWN0KGNvbCkgJT4lIA0KICAgIHB1bGwoKSAlPiUgDQogICAgc3RyX2NvdW50KHNlcCkgJT4lIA0KICAgIG1heCgpDQogIA0KICANCn0NCmBgYA0KDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmVtaXNzaW9uc19sb25nIDwtIGJpbmRfcm93cyhsaXN0KHBhcmVudHMsIGZpcnN0X2Jvcm4sIHNlY29uZF9ib3JuLCB0aGlyZF9ib3JuKSkgJT4lIA0KICBtdXRhdGUodW5pdHMgPSBnaGdfZW1pc3Npb25zX2NsZWFuJHVuaXRzWzFdKSAlPiUgDQogIHdyaXRlX2NzdigiZGF0YS9jbGVhbl9kYXRhL2hpZXJhcmNoaWNhbF9kYXRhLmNzdiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZW1pc3Npb25zX2xvbmcgJT4lDQogIGRhdGEuZnJhbWUoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSAlPiUgDQogIHBsb3RfbHkoDQogICAgaWRzID0gfmlkLA0KICAgIGxhYmVscyA9IH5sYWJlbCwNCiAgICBwYXJlbnRzID0gfnBhcmVudCwNCiAgICB2YWx1ZXMgPSB+dmFsdWUsDQogICAgdHlwZSA9ICJ0cmVlbWFwIiwNCiAgICBicmFuY2h2YWx1ZXMgPSAidG90YWwiLA0KICAgIG1heGRlcHRoID0gMiwNCiAgICB0ZXh0aW5mbz0nbGFiZWwrcGVyY2VudCByb290K2VudHJ5Jw0KICApDQpgYGANCg0KDQpgYGB7cn0NCmVtaXNzaW9uc19sb25nICU+JSANCiAgZGF0YS5mcmFtZShzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICU+JSANCiAgcGxvdF9seSgNCiAgICBpZHMgPSB+aWQsDQogICAgbGFiZWxzID0gfmxhYmVsLA0KICAgIHBhcmVudHMgPSB+cGFyZW50LA0KICAgIHZhbHVlcyA9IH52YWx1ZSwNCiAgICB0eXBlID0gInN1bmJ1cnN0IiwNCiAgICBtYXhkZXB0aCA9IDIsDQogICAgaW5zaWRldGV4dG9yaWVudGF0aW9uID0gJ3JhZGlhbCcsDQogICAgbWFya2VyPWxpc3QoY29sb3JzY2FsZT0nUG9ydGxhbmQnKSwNCiAgICB0ZXh0ID0gfnVuaXRzLA0KICAgIHRleHRpbmZvPSdsYWJlbCtwZXJjZW50IHJvb3QrcGVyY2VudCBlbnRyeScsDQogICAgaG92ZXJpbmZvID0gcGFzdGUoIiV7bGFiZWx9OiA8YnI+JXt2YWx1ZX0iLCd0ZXh0JykNCiAgKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnBsb3RfbHkoDQogIGxhYmVscyA9IGMoIkV2ZSIsICJTZXRoIiwgIkVub3MiLCAiTm9hbSIsICJBd2FuIiwgIkVub2NoIiksDQogIHBhcmVudHMgPSBjKCIiLCAiRXZlIiwgIlNldGgiLCAiU2V0aCIsICJFdmUiLCAiQXdhbiIpLA0KICB2YWx1ZXMgPSBjKDE2LCAxMiwgMTAsIDIsIDQsIDQpLA0KICB0eXBlID0gInN1bmJ1cnN0IiwNCiAgYnJhbmNodmFsdWVzID0gInRvdGFsIg0KKQ0KYGBgDQoNCmBgYHtyfQ0KdGliYmxlKA0KICBsYWJlbHMgPSBjKCJFdmUiLCAiU2V0aCIsICJFbm9zIiwgIk5vYW0iLCAiQXdhbiIsICJFbm9jaCIpLA0KICBwYXJlbnRzID0gYygiIiwgIkV2ZSIsICJTZXRoIiwgIlNldGgiLCAiRXZlIiwgIkF3YW4iKSwNCiAgdmFsdWVzID0gYygxNiwgMTIsIDEwLCAyLCA0LCA0KQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KZW1pc3Npb25zX2xvbmcNCmBgYA0KDQoNCmBgYHtyfQ0KZmlnIDwtIHBsb3RfbHkoDQogIGxhYmVscyA9IGNhaW5fYmxlJGxhYmVscywNCiAgcGFyZW50cyA9IGNhaW5fYmxlJHBhcmVudHMsDQogIHZhbHVlcyA9IGNhaW5fYmxlJHZhbHVlcywNCiAgdHlwZSA9ICdzdW5idXJzdCcNCikNCg0KZmlnDQpgYGANCg0KDQpgYGB7cn0NCmVtaXNzaW9uc19sb25nJGxhYmVsWzE6MTBdDQpgYGANCg0KDQpgYGB7cn0NCmQgPC0gZGF0YS5mcmFtZSgNCiAgICBpZHMgPSBjKA0KICAgICJOb3J0aCBBbWVyaWNhIiwgIkV1cm9wZSIsICJBdXN0cmFsaWEiLCAiTm9ydGggQW1lcmljYSAtIEZvb3RiYWxsIiwgIlNvY2NlciIsDQogICAgIk5vcnRoIEFtZXJpY2EgLSBSdWdieSIsICJFdXJvcGUgLSBGb290YmFsbCIsICJSdWdieSIsDQogICAgIkV1cm9wZSAtIEFtZXJpY2FuIEZvb3RiYWxsIiwiQXVzdHJhbGlhIC0gRm9vdGJhbGwiLCAiQXNzb2NpYXRpb24iLA0KICAgICJBdXN0cmFsaWFuIFJ1bGVzIiwgIkF1dHN0cmFsaWEgLSBBbWVyaWNhbiBGb290YmFsbCIsICJBdXN0cmFsaWEgLSBSdWdieSIsDQogICAgIlJ1Z2J5IExlYWd1ZSIsICJSdWdieSBVbmlvbiINCiAgKSwNCiAgbGFiZWxzID0gYygNCiAgICAiTm9ydGg8YnI+QW1lcmljYSIsICJFdXJvcGUiLCAiQXVzdHJhbGlhIiwgIkZvb3RiYWxsIiwgIlNvY2NlciIsICJSdWdieSIsDQogICAgIkZvb3RiYWxsIiwgIlJ1Z2J5IiwgIkFtZXJpY2FuPGJyPkZvb3RiYWxsIiwgIkZvb3RiYWxsIiwgIkFzc29jaWF0aW9uIiwNCiAgICAiQXVzdHJhbGlhbjxicj5SdWxlcyIsICJBbWVyaWNhbjxicj5Gb290YmFsbCIsICJSdWdieSIsICJSdWdieTxicj5MZWFndWUiLA0KICAgICJSdWdieTxicj5VbmlvbiINCiAgKSwNCiAgcGFyZW50cyA9IGMoDQogICAgIiIsICIiLCAiIiwgIk5vcnRoIEFtZXJpY2EiLCAiTm9ydGggQW1lcmljYSIsICJOb3J0aCBBbWVyaWNhIiwgIkV1cm9wZSIsDQogICAgIkV1cm9wZSIsICJFdXJvcGUiLCJBdXN0cmFsaWEiLCAiQXVzdHJhbGlhIC0gRm9vdGJhbGwiLCAiQXVzdHJhbGlhIC0gRm9vdGJhbGwiLA0KICAgICJBdXN0cmFsaWEgLSBGb290YmFsbCIsICJBdXN0cmFsaWEgLSBGb290YmFsbCIsICJBdXN0cmFsaWEgLSBSdWdieSIsDQogICAgIkF1c3RyYWxpYSAtIFJ1Z2J5Ig0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KZmlnIDwtIHBsb3RfbHkoZCwgaWRzID0gfmlkcywgbGFiZWxzID0gfmxhYmVscywgcGFyZW50cyA9IH5wYXJlbnRzLCB0eXBlID0gJ3N1bmJ1cnN0JykNCg0KZA0KYGBgDQoNCmBgYHtyfQ0KY2xhc3MoZW1pc3Npb25zX2xvbmcpDQpgYGANCmBgYHtyfQ0KY2xhc3MoY2Fpbl9ibGUpDQpgYGANCg0KDQpgYGB7cn0NCmRpZmZfb3JkZXIgPC0gZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjY3BfbWFwcGluZywgeWVhciwgcG9sbHV0YW50KSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCB1bml0cyA9IHVuaXRzWzFdLCAuZ3JvdXBzID0gImtlZXAiKSAlPiUNCiAgZmlsdGVyKHBvbGx1dGFudCA9PSAiQ08yIikgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSBtaW4oZ2hnX2VtaXNzaW9uc19jbGVhbiR5ZWFyKSB8DQogICAgICAgICAgIHllYXIgPT0gbWF4KGdoZ19lbWlzc2lvbnNfY2xlYW4keWVhcikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZ3JvdXBfYnkoY2NwX21hcHBpbmcpICU+JSANCiAgbXV0YXRlKGRpZmYgPSBsYWcodmFsdWUpIC0gdmFsdWUpICU+JSANCiAgYXJyYW5nZShkaWZmKSAlPiUNCiAgZHJvcF9uYSgpICU+JSANCiAgc2VsZWN0KGNjcF9tYXBwaW5nKSAlPiUgDQogIHB1bGwoKQ0KYGBgDQoNCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2NsZWFuICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNjcF9tYXBwaW5nLCB5ZWFyLCBwb2xsdXRhbnQpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIHVuaXRzID0gdW5pdHNbMV0sIC5ncm91cHMgPSAia2VlcCIpICU+JQ0KICBmaWx0ZXIocG9sbHV0YW50ID09ICJDTzIiKSAlPiUNCiAgbXV0YXRlKGNjcF9tYXBwaW5nID0gZmFjdG9yKGNjcF9tYXBwaW5nLCBsZXZlbHMgPSByZXYoZGlmZl9vcmRlcikpKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGZpbGwgPSBjY3BfbWFwcGluZykgKw0KICBnZW9tX2FyZWEoKSArDQogIGZhY2V0X3dyYXAofnBvbGx1dGFudCkgKw0KICB0aGVtZV9idygpDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUgDQogIGdyb3VwX2J5KHBvbGx1dGFudCkgJT4lIA0KICBzdW1tYXJpc2UoZW1pc3Npb25zID0gc3VtKHZhbHVlKSkNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdGx5OjpnZ3Bsb3RseSgNCiAgZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUgDQogICAgZmlsdGVyKHllYXIgPT0gMjAxOCkgJT4lDQogICAgZmlsdGVyKHBvbGx1dGFudCAlaW4lIGMoIkNPMiIsICJDSDQiKSkgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyh4ID0gZmFjdG9yKGNjcF9tYXBwaW5nLCBsZXZlbHMgPSByZXYobGV2ZWxzKGZhY3RvcihjY3BfbWFwcGluZykpKSksDQogICAgICAgIHkgPSB2YWx1ZSwgZmlsbCA9IHNvdXJjZV9uYW1lLA0KICAgICAgICB0ZXh0ID0gcGFzdGUwKCc8L2JyPiBTZWN0b3I6ICcsIGNjcF9tYXBwaW5nLA0KICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiBFbWlzc2lvbnM6ICcsIHZhbHVlLA0KICAgICAgICAgICAgICAgICAgICAgICc8L2JyPiBTb3VyY2UgTmFtZTogJywgc291cmNlX25hbWUpKSArDQogICAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siKSArDQogICAgdGhlbWVfYncoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogICAgbGFicyh4ID0gIlNlY3RvciIsDQogICAgICAgICB5ID0gcGFzdGUwKCJFbWlzc2lvbnMgKCIsIGdoZ19lbWlzc2lvbnNfY2xlYW4kdW5pdHNbMV0sICIpIikpICsNCiAgICBjb29yZF9mbGlwKCksDQogICAgdG9vbHRpcCA9ICd0ZXh0Jw0KICApDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgbmFtZXMoKQ0KYGBgDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgc2VsZWN0KCkNCmBgYA0KDQoNCg0KYGBge3J9DQppbnB1dCA8LSBsaXN0KCkNCg0KaW5wdXQkY29sX2Nob2ljZSA9ICJuYXRpb25hbF9jb21tdW5pY2F0aW9uX2NhdGVnb3JpZXMiDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUNCiAgZ3JvdXBfYnlfKGlucHV0JGNvbF9jaG9pY2UsICJlbWlzc2lvbl95ZWFyIikgJT4lIA0KICBzdW1tYXJpc2UodG90YWxfZ2hnX2VtaXNzaW9ucyA9IHN1bShlbWlzc2lvbnMpKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSBFbWlzc2lvblllYXIsIHkgPSB0b3RhbF9naGdfZW1pc3Npb25zLCBncm91cCA9IGBOYXRpb25hbCBDb21tdW5pY2F0aW9uIENhdGVnb3JpZXNgLCBjb2xvdXIgPSBgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk5MCwyMDIwLDUpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IDApDQpgYGANCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBkaXN0aW5jdChgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCkNCmBgYA0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBmaWx0ZXIoRW1pc3Npb25ZZWFyICE9ICJCYXNlWWVhciIpICU+JSANCiAgbXV0YXRlKEVtaXNzaW9uWWVhciA9IGFzLm51bWVyaWMoRW1pc3Npb25ZZWFyKSkgJT4lIA0KICBncm91cF9ieShFbWlzc2lvblllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2doZ19lbWlzc2lvbnMgPSBzdW0oYEVtaXNzaW9ucyAoTXRDTzJlKWApKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSBFbWlzc2lvblllYXIsIHkgPSB0b3RhbF9naGdfZW1pc3Npb25zKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTkwLDIwMjAsNSkpICsNCiAgeWxpbSgwLCA4MCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAwKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZGlzdGluY3QoYENDUCBtYXBwaW5nYCkNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBkaXN0aW5jdChgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCkNCmBgYA0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGENCmBgYA0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBmaWx0ZXIoRW1pc3Npb25ZZWFyICE9ICJCYXNlWWVhciIpICU+JSANCiAgbXV0YXRlKEVtaXNzaW9uWWVhciA9IGFzLm51bWVyaWMoRW1pc3Npb25ZZWFyKSkgJT4lIA0KICBncm91cF9ieShgQ0NQIG1hcHBpbmdgLCBFbWlzc2lvblllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2doZ19lbWlzc2lvbnMgPSBzdW0oYEVtaXNzaW9ucyAoTXRDTzJlKWApKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSBFbWlzc2lvblllYXIsIHkgPSB0b3RhbF9naGdfZW1pc3Npb25zLCBncm91cCA9IGBDQ1AgbWFwcGluZ2AsIGNvbG91ciA9IGBDQ1AgbWFwcGluZ2ApICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5OTAsMjAyMCw1KSkNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIGZpbHRlcihFbWlzc2lvblllYXIgIT0gIkJhc2VZZWFyIikgJT4lIA0KICBtdXRhdGUoRW1pc3Npb25ZZWFyID0gYXMubnVtZXJpYyhFbWlzc2lvblllYXIpKSAlPiUgDQogIGZpbHRlcihgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCAhPSBgQ0NQIG1hcHBpbmdgKSAlPiUgDQogIHNlbGVjdChgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCwgYENDUCBtYXBwaW5nYCkgJT4lIA0KICB1bmlxdWUoKQ0KYGBgDQpjYXRlZ29yeV9pZCxjYXRlZ29yeV9uYW1lLHN1YmNhdGVnb3J5X2lkLHN1YmNhdGVnb3J5X25hbWUseWVhcixlbWlzc2lvbnMsZW1pc3Npb24NCg0KYGBge3J9DQplbWlzc2lvbnNfc2Fua2V5IDwtIGVtaXNzaW9uc19kYXRhICU+JSANCiAgc2VsZWN0KGNjcF9tYXBwaW5nLCBzb3VyY2VfbmFtZSwgcG9sbHV0YW50LCBlbWlzc2lvbl95ZWFyLCBlbWlzc2lvbnMsIHVuaXRzKQ0KYGBgDQoNCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2NsZWFuDQpgYGANCg0KDQpgYGB7cn0NCmZpbHRlcmVkX2RmIDwtIGdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBzZWxlY3QoY2NwX21hcHBpbmcsIHNvdXJjZV9uYW1lLCBwb2xsdXRhbnQsIGVtaXNzaW9uX3llYXIsIGVtaXNzaW9ucywgdW5pdHMpICU+JSANCiAgZmlsdGVyKHBvbGx1dGFudCA9PSAiQ08yIikgJT4lIA0KICBmaWx0ZXIoZW1pc3Npb25feWVhciA9PSAiMjAwNSIpDQpgYGANCg0KYGBge3J9DQp0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIHN1bW1hcmlzZShzdW0oZW1pc3Npb25zKSkgJT4lIA0KICBwdWxsKCkNCg0KdG90YWxfZW1pc3Npb25zX2J5X2NhdGVnb3J5IDwtIGZpbHRlcmVkX2RmICU+JSANCiAgc2VsZWN0KC1wb2xsdXRhbnQpICU+JSANCiAgZ3JvdXBfYnkoY2NwX21hcHBpbmcpICU+JSANCiAgc3VtbWFyaXNlKGNhdF9zdW0gPSBzdW0oZW1pc3Npb25zKSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0ZWdvcmllcyA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIGRpc3RpbmN0KGNjcF9tYXBwaW5nKSAlPiUgDQogIHB1bGwoKQ0KDQpuX2NhdGVnb3JpZXMgPC0gbGVuZ3RoKGNhdGVnb3JpZXMpDQoNCnNvdXJjZXMgPC0gZmlsdGVyZWRfZGYgJT4lIA0KICBkaXN0aW5jdChzb3VyY2VfbmFtZSkgJT4lIA0KICBwdWxsKCkNCg0Kbl9zb3VyY2VzIDwtIGxlbmd0aChzb3VyY2VzKQ0KYGBgDQoNCmBgYHtyfQ0Kbl9zb3VyY2VzDQpgYGANCg0KDQpgYGB7cn0NCm5vZGVfbmFtZXMgPC0gYygiVG90YWwiLCBjYXRlZ29yaWVzLCBzb3VyY2VzLCAiT3RoZXIiKQ0KDQpub2RlX25hbWVzX2RmIDwtIGRhdGEuZnJhbWUoIm5hbWUiID0gbm9kZV9uYW1lcykNCg0KdG90YWxfc2Fua2V5X3RpYmJsZSA8LSB0b3RhbF9lbWlzc2lvbnNfYnlfY2F0ZWdvcnkgJT4lDQogIG11dGF0ZSh0b3RhbCA9ICJUb3RhbCIpICU+JSANCiAgbXV0YXRlKHRvdGFsID0gbWF0Y2godG90YWwsIG5vZGVfbmFtZXMpIC0xKSAlPiUgDQogIG11dGF0ZShjY3BfbWFwcGluZyA9IG1hdGNoKGNjcF9tYXBwaW5nLCBub2RlX25hbWVzKSAtMSkgJT4lIA0KICBzZWxlY3Qoc291cmNlID0gdG90YWwsDQogICAgICAgICB0YXJnZXQgPSBjY3BfbWFwcGluZywNCiAgICAgICAgIHZhbHVlID0gY2F0X3N1bSkNCg0KdG90YWxfZmlsdGVyZWRfZW1pc3Npb25zIDwtIHRvdGFsX3NhbmtleV90aWJibGUgJT4lIA0KICBzdW1tYXJpc2Uoc3VtKHZhbHVlKSkgJT4lIA0KICBwdWxsKCkNCg0Kb3RoZXJfZW1pc3Npb25zIDwtIHRvdGFsX2VtaXNzaW9uc19mb3JfZ2FzIC0gdG90YWxfZmlsdGVyZWRfZW1pc3Npb25zDQoNCnRvdGFsX290aGVyX3NhbmtleV90aWJibGUgPC0gdGliYmxlKA0KICAic291cmNlIiA9IGMoMCksDQogICJ0YXJnZXQiID0gKG1hdGNoKCJPdGhlciIsIG5vZGVfbmFtZXMpIC0xKSwNCiAgInZhbHVlIiA9IGMob3RoZXJfZW1pc3Npb25zKQ0KKQ0KDQoNCnN1Yl9zYW5rZXlfdGliYmxlIDwtIGZpbHRlcmVkX2RmICU+JSANCiAgc2VsZWN0KC0gYyh1bml0cywgcG9sbHV0YW50LCBlbWlzc2lvbl95ZWFyKSkgJT4lIA0KICBtdXRhdGUoY2NwX21hcHBpbmcgPSBtYXRjaChjY3BfbWFwcGluZywgbm9kZV9uYW1lcykgLTEsDQogICAgICAgICBzb3VyY2VfbmFtZSA9IG1hdGNoKHNvdXJjZV9uYW1lLCBub2RlX25hbWVzKSAtMSkNCg0KbmFtZXMoc3ViX3NhbmtleV90aWJibGUpID0gYygic291cmNlIiwgInRhcmdldCIsICJ2YWx1ZSIpDQoNCnNhbmtleV90aWJibGUgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogIGJpbmRfcm93cyhzdWJfc2Fua2V5X3RpYmJsZSkgJT4lIA0KICBiaW5kX3Jvd3ModG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSkNCg0KbGlua3NfbWF0cml4IDwtIGRhdGEuZnJhbWUoYXMubWF0cml4KHNhbmtleV90aWJibGUsIGJ5cm93ID0gVFJVRSwgbmNvbHMgPSAzKSkNCg0KIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIGNvbm5lY3Rpb246DQpsaW5rcyA8LSBsaW5rc19tYXRyaXggJT4lIA0KICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgc291cmNlID09IDAgfiBwYXN0ZSgidHlwZV8iLCB0YXJnZXQsIHNlcCA9ICIiKSwNCiAgICBzb3VyY2UhPTAgfiBwYXN0ZSgidHlwZV8iLCBzb3VyY2UsIHNlcCA9ICIiKQ0KICApKQ0KDQpub2RlcyA8LSBub2RlX25hbWVzX2RmDQojIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggbm9kZS4NCiMgQWxsIG9mIHRoZW0gaW4gdGhlIHNhbWUgZ3JvdXAgdG8gbWFrZSB0aGVtIHRoZSBzYW1lIGNvbG91cg0Kbm9kZXMkZ3JvdXAgPC0gYXMuZmFjdG9yKGMoIm15X3VuaXF1ZV9ncm91cCIpKQ0KDQplbWlzc2lvbnMgPC0gbGlzdCgpDQoNCmVtaXNzaW9ucyRub2RlcyA8LSBub2Rlcw0KZW1pc3Npb25zJGxpbmtzIDwtIGxpbmtzDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQpgYGB7cn0NCnRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucyA8LSB0b3RhbF9zYW5rZXlfdGliYmxlICU+JSANCiAgc3VtbWFyaXNlKHN1bSh2YWx1ZSkpICU+JSANCiAgcHVsbCgpDQoNCm90aGVyX2VtaXNzaW9ucyA8LSB0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyAtIHRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucw0KDQp0b3RhbF9vdGhlcl9zYW5rZXlfdGliYmxlIDwtIHRpYmJsZSgNCiAgInNvdXJjZSIgPSBjKDApLA0KICAidGFyZ2V0IiA9IChtYXRjaCgiT3RoZXIiLCBub2RlX25hbWVzKSAtMSksDQogICJ2YWx1ZSIgPSBjKG90aGVyX2VtaXNzaW9ucykNCikNCg0Kc3ViX3NhbmtleV90aWJibGUgPC0gZmlsdGVyZWRfdGliYmxlICU+JSANCiAgc2VsZWN0KC1jYXRlZ29yeV9pZCwgLXN1YmNhdGVnb3J5X2lkLCAteWVhcikgJT4lIA0KICBtdXRhdGUoY2F0ZWdvcnlfbmFtZSA9IG1hdGNoKGNhdGVnb3J5X25hbWUsIG5vZGVfbmFtZXMpIC0xLA0KICAgICAgICAgc3ViY2F0ZWdvcnlfbmFtZSA9IG1hdGNoKHN1YmNhdGVnb3J5X25hbWUsIG5vZGVfbmFtZXMpIC0xKQ0KDQpuYW1lcyhzdWJfc2Fua2V5X3RpYmJsZSkgPSBjKCJzb3VyY2UiLCAidGFyZ2V0IiwgInZhbHVlIikNCg0Kc2Fua2V5X3RpYmJsZSA8LSB0b3RhbF9zYW5rZXlfdGliYmxlICU+JSANCiAgYmluZF9yb3dzKHN1Yl9zYW5rZXlfdGliYmxlKSAlPiUgDQogIGJpbmRfcm93cyh0b3RhbF9vdGhlcl9zYW5rZXlfdGliYmxlKQ0KDQpsaW5rc19tYXRyaXggPC0gZGF0YS5mcmFtZShhcy5tYXRyaXgoc2Fua2V5X3RpYmJsZSwgYnlyb3cgPSBUUlVFLCBuY29scyA9IDMpKQ0KDQojIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggY29ubmVjdGlvbjoNCmxpbmtzIDwtIGxpbmtzX21hdHJpeCAlPiUgDQogIG11dGF0ZShncm91cCA9IGNhc2Vfd2hlbigNCiAgICBzb3VyY2UgPT0gMCB+IHBhc3RlKCJ0eXBlXyIsIHRhcmdldCwgc2VwID0gIiIpLA0KICAgIHNvdXJjZSE9MCB+IHBhc3RlKCJ0eXBlXyIsIHNvdXJjZSwgc2VwID0gIiIpDQogICkpDQoNCm5vZGVzIDwtIG5vZGVfbmFtZXNfZGYNCiMgQWRkIGEgJ2dyb3VwJyBjb2x1bW4gdG8gZWFjaCBub2RlLg0KIyBBbGwgb2YgdGhlbSBpbiB0aGUgc2FtZSBncm91cCB0byBtYWtlIHRoZW0gdGhlIHNhbWUgY29sb3VyDQpub2RlcyRncm91cCA8LSBhcy5mYWN0b3IoYygibXlfdW5pcXVlX2dyb3VwIikpDQoNCmVtaXNzaW9ucyA8LSBsaXN0KCkNCg0KZW1pc3Npb25zJG5vZGVzIDwtIG5vZGVzDQplbWlzc2lvbnMkbGlua3MgPC0gbGlua3MNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCmBgYHtyfQ0KbWFrZV9zYW5rZXlfZGZzIDwtIGZ1bmN0aW9uKGRhdGEsIHVzZXJZZWFyLCB1c2VyR2FzKSB7DQogIG5fY2F0ZWdvcmllcyA8LSBkYXRhICU+JSANCiAgICBkaXN0aW5jdChjYXRlZ29yeV9uYW1lKSAlPiUgDQogICAgbnJvdygpDQogIA0KICB0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyA8LSBkYXRhICU+JSANCiAgICBmaWx0ZXIoZW1pc3Npb24gPT0gdXNlckdhcygpKSAlPiUgDQogICAgZmlsdGVyKHllYXIgPT0gdXNlclllYXIoKSkgJT4lDQogICAgc3VtbWFyaXNlKHN1bShlbWlzc2lvbnMpKSAlPiUgDQogICAgcHVsbCgpDQogIA0KICBmaWx0ZXJlZF90aWJibGUgPC0gZGF0YSAlPiUNCiAgICBmaWx0ZXIoZW1pc3Npb24gPT0gdXNlckdhcygpKSAlPiUgDQogICAgc2VsZWN0KC1lbWlzc2lvbikgJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IHVzZXJZZWFyKCkpICU+JSANCiAgICBmaWx0ZXIoZW1pc3Npb25zID4gdXNlclJlc29sdXRpb24oKSkNCiAgDQogIHRvdGFsX2VtaXNzaW9uc19ieV9jYXQgPC0gZmlsdGVyZWRfdGliYmxlICU+JQ0KICAgIGdyb3VwX2J5KGNhdGVnb3J5X25hbWUpICU+JSANCiAgICBzdW1tYXJpc2UoY2F0X3N1bSA9IHN1bShlbWlzc2lvbnMpLCAuZ3JvdXBzID0gJ2Ryb3BfbGFzdCcpDQogIA0KICBjYXRlZ29yaWVzIDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUNCiAgICBkaXN0aW5jdChjYXRlZ29yeV9uYW1lKSAlPiUgDQogICAgcHVsbCgpDQogIA0KICBzdWJjYXRlZ29yaWVzIDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUNCiAgICBkaXN0aW5jdChzdWJjYXRlZ29yeV9uYW1lKSAlPiUgDQogICAgcHVsbCgpDQogIA0KICBub2RlX25hbWVzIDwtIGMoIlRvdGFsIiwgY2F0ZWdvcmllcywgc3ViY2F0ZWdvcmllcywgIk90aGVyIikNCiAgDQogIG5vZGVfbmFtZXNfZGYgPC0gZGF0YS5mcmFtZSgibmFtZSIgPSBub2RlX25hbWVzKQ0KICANCiAgdG90YWxfc2Fua2V5X3RpYmJsZSA8LSB0b3RhbF9lbWlzc2lvbnNfYnlfY2F0ICU+JQ0KICAgIG11dGF0ZSh0b3RhbCA9ICJUb3RhbCIpICU+JSANCiAgICBtdXRhdGUodG90YWwgPSBtYXRjaCh0b3RhbCwgbm9kZV9uYW1lcykgLTEpICU+JSANCiAgICBtdXRhdGUoY2F0ZWdvcnlfbmFtZSA9IG1hdGNoKGNhdGVnb3J5X25hbWUsIG5vZGVfbmFtZXMpIC0xKSAlPiUgDQogICAgc2VsZWN0KHNvdXJjZSA9IHRvdGFsLA0KICAgICAgICAgICB0YXJnZXQgPSBjYXRlZ29yeV9uYW1lLA0KICAgICAgICAgICB2YWx1ZSA9IGNhdF9zdW0pDQogIA0KICB0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogICAgc3VtbWFyaXNlKHN1bSh2YWx1ZSkpICU+JSANCiAgICBwdWxsKCkNCiAgDQogIG90aGVyX2VtaXNzaW9ucyA8LSB0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyAtIHRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucw0KICANCiAgdG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSA8LSB0aWJibGUoDQogICAgInNvdXJjZSIgPSBjKDApLA0KICAgICJ0YXJnZXQiID0gKG1hdGNoKCJPdGhlciIsIG5vZGVfbmFtZXMpIC0xKSwNCiAgICAidmFsdWUiID0gYyhvdGhlcl9lbWlzc2lvbnMpDQogICkNCiAgDQogIHN1Yl9zYW5rZXlfdGliYmxlIDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUgDQogICAgc2VsZWN0KC1jYXRlZ29yeV9pZCwgLXN1YmNhdGVnb3J5X2lkLCAteWVhcikgJT4lIA0KICAgIG11dGF0ZShjYXRlZ29yeV9uYW1lID0gbWF0Y2goY2F0ZWdvcnlfbmFtZSwgbm9kZV9uYW1lcykgLTEsDQogICAgICAgICAgIHN1YmNhdGVnb3J5X25hbWUgPSBtYXRjaChzdWJjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSkNCiAgDQogIG5hbWVzKHN1Yl9zYW5rZXlfdGliYmxlKSA9IGMoInNvdXJjZSIsICJ0YXJnZXQiLCAidmFsdWUiKQ0KICANCiAgc2Fua2V5X3RpYmJsZSA8LSB0b3RhbF9zYW5rZXlfdGliYmxlICU+JSANCiAgICBiaW5kX3Jvd3Moc3ViX3NhbmtleV90aWJibGUpICU+JSANCiAgICBiaW5kX3Jvd3ModG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSkNCiAgDQogIGxpbmtzX21hdHJpeCA8LSBkYXRhLmZyYW1lKGFzLm1hdHJpeChzYW5rZXlfdGliYmxlLCBieXJvdyA9IFRSVUUsIG5jb2xzID0gMykpDQogIA0KICAjIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggY29ubmVjdGlvbjoNCiAgbGlua3MgPC0gbGlua3NfbWF0cml4ICU+JSANCiAgICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgICBzb3VyY2UgPT0gMCB+IHBhc3RlKCJ0eXBlXyIsIHRhcmdldCwgc2VwID0gIiIpLA0KICAgICAgc291cmNlIT0wIH4gcGFzdGUoInR5cGVfIiwgc291cmNlLCBzZXAgPSAiIikNCiAgICApKQ0KICANCiAgbm9kZXMgPC0gbm9kZV9uYW1lc19kZg0KICAjIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggbm9kZS4NCiAgIyBBbGwgb2YgdGhlbSBpbiB0aGUgc2FtZSBncm91cCB0byBtYWtlIHRoZW0gdGhlIHNhbWUgY29sb3VyDQogIG5vZGVzJGdyb3VwIDwtIGFzLmZhY3RvcihjKCJteV91bmlxdWVfZ3JvdXAiKSkNCiAgDQogIGVtaXNzaW9ucyA8LSBsaXN0KCkNCiAgDQogIGVtaXNzaW9ucyRub2RlcyA8LSBub2Rlcw0KICBlbWlzc2lvbnMkbGlua3MgPC0gbGlua3MNCiAgDQogIHJldHVybihlbWlzc2lvbnMpDQp9DQpgYGANCg0KDQpgYGB7cn0NCm1ha2Vfc2Fua2V5X2RmcyhlbWlzc2lvbnNfc2Fua2V5LCB1c2VyWWVhciA9IDIwMDUsIHVzZXJHYXMgPSAiQ0g0IiwgdXNlclJlc29sdXRpb24gPSA1MCkNCmBgYA0KYGBge3J9DQoNCmBgYA0KDQo=